/*
 * 文 件 名:  JpaQueryServiceImpl.java
 * 版    权:  Ysten Technologies Co., Ltd. Copyright YYYY-YYYY,  All rights reserved
 * 描    述:  <描述>
 * 修 改 人:  bo.chen
 * 修改时间:  2014年11月10日
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package lv.pig.base.jpa.service.impl;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import lv.pig.base.jpa.service.JpaQueryService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author bo.chen
 * @version [版本号, 2014年11月10日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service("JpaQueryService")
public class JpaQueryServiceImpl<T> implements JpaQueryService<T>
{
    @PersistenceContext
    private EntityManager em;
    
    public List<T> findListBySql(String sql, Object... args)
    {
        return this.findListBySql(sql, 0, Integer.MAX_VALUE, args);
    }
    
    @SuppressWarnings("unchecked")
    private List<T> findListBySql(String sql, Integer pageNo, Integer pageSize, Object... args)
    {
        
        try
        {
            Query query = em.createQuery(sql);
            if (args.length > 0)
            {
                int i = 1;
                for (Object o : args)
                {
                    if (null != o)
                        query.setParameter(i++, o);
                }
            }
            query.setFirstResult(pageNo * pageSize);
            query.setMaxResults(pageSize);
            return query.getResultList();
        }
        finally
        {
            if (em != null)
            {
                em.clear();
                em.close();
            }
        }
    }
    
    @SuppressWarnings("unchecked")
    public T findBySql(String sql, Object... args)
    {
        
        try
        {
            Query query = em.createQuery(sql);
            if (args.length > 0)
            {
                int i = 1;
                for (Object o : args)
                {
                    if (null != o)
                        query.setParameter(i++, o);
                }
            }
            query.setFirstResult(0);
            query.setMaxResults(1);
            return (T)query.getSingleResult();
        }
        finally
        {
            if (em != null)
            {
                em.clear();
                em.close();
            }
        }
    }
    
    @Override
    public Page<T> findPageBySql(String sql, Pageable pageable, Object... args)
    {
        int pageNo = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();
        // for mysql 使用 select * from t_table limit 0,5
        int sql_index = sql.indexOf("from");
        
        String countStr = "select count(*) " + sql.substring(sql_index);
        
        Long total = (Long)this.findBySql(countStr.toString(), args);
        return new PageImpl<T>(this.findListBySql(sql, pageNo, pageSize, args), pageable, total);
    }
    
    @Override
    public List<T> findListByNativeSql(String sql, Class<?> c, Object... args)
    {
        return this.findListByNativeSql(sql, c, 0, Integer.MAX_VALUE, args);
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T findByNativeSql(String sql, Class<?> c, Object... args)
    {
        
        try
        {
            Query query = (null == c ? em.createNativeQuery(sql) : em.createNativeQuery(sql, c));
            if (args.length > 0)
            {
                int i = 1;
                for (Object o : args)
                {
                    if (null != o)
                        query.setParameter(i++, o);
                }
            }
            query.setFirstResult(0);
            query.setMaxResults(1);
            return (T)query.getSingleResult();
        }
        finally
        {
            if (em != null)
            {
                em.clear();
                em.close();
            }
        }
    }
    
    @Override
    public Page<T> findPageByNativeSql(String sql, Class<?> c, Pageable pageable, Object... args)
    {
        int pageNo = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();
        // for mysql 使用 select * from t_table limit 0,5
        int sql_index = sql.indexOf("from");
        
        String countStr = "select count(*) " + sql.substring(sql_index);
        // 总条数 bigint
        Long total = Long.valueOf(this.findByNativeSql(countStr.toString(), null, args).toString());
        return new PageImpl<T>(this.findListByNativeSql(sql, c, pageNo, pageSize, args), pageable, total);
    }
    
    @SuppressWarnings("unchecked")
    private List<T> findListByNativeSql(String sql, Class<?> c, Integer pageNo, Integer pageSize, Object... args)
    {
        
        try
        {
            
            Query query = (null == c ? em.createNativeQuery(sql) : em.createNativeQuery(sql, c));
            if (args.length > 0)
            {
                int i = 1;
                for (Object o : args)
                {
                    if (null != o)
                        query.setParameter(i++, o);
                }
            }
            query.setFirstResult(pageNo * pageSize);
            query.setMaxResults(pageSize);
            return query.getResultList();
        }
        finally
        {
            if (em != null)
            {
                em.clear();
                em.close();
            }
        }
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public List<T> findListByNativeSql(String sql, Object... args)
    {
        
        try
        {
            Query query = em.createNativeQuery(sql);
            if (args.length > 0)
            {
                int i = 1;
                for (Object o : args)
                {
                    if (null != o)
                        query.setParameter(i++, o);
                }
            }
            return query.getResultList();
        }
        finally
        {
            if (em != null)
            {
                em.clear();
                em.close();
            }
        }
        
    }
    
    @Override
    public T findByNativeSql(String sql, Object... args)
    {
        return this.findByNativeSql(sql, null, args);
    }
}
